package com.ruoyi.system.service.impl;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.google.gson.Gson;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.domain.TxcheckVO;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.*;
import com.ruoyi.common.utils.http.HttpClientUtil;
import com.ruoyi.common.utils.property.WeChatProperty;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.domain.dto.AUserDto;
import com.ruoyi.system.domain.vo.*;
import com.ruoyi.system.mapper.*;
import com.ruoyi.system.service.IAOperationRecordsService;
import com.ruoyi.system.service.IATeamService;
import com.ruoyi.system.util.LoginUtils;
import io.jsonwebtoken.lang.Assert;
import lombok.val;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.system.service.IAUserService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

/**
 * 小程序用户Service业务层处理
 *
 * @author ruoyi
 * @date 2024-05-16
 */
@Service
public class AUserServiceImpl implements IAUserService
{
    @Autowired
    private AUserMapper aUserMapper;

    @Autowired
    private AInformationMapper aInformationMapper;

    @Autowired
    private ADataInfoMapper aDataInfoMapper;

    @Autowired
    private IAOperationRecordsService aOperationRecordsService;
    @Resource
    private IATeamService aTeamService;
    @Resource
    private ATeamMapper aTeamMapper;
    @Resource
    private ATeamInfoMapper aTeamInfoMapper;

    private static RedisCache redisService = SpringUtils.getBean(RedisCache.class);

    private String  gzhAppId = SpringUtils.getBean(WeChatProperty.class).getGzhAppId();
    private String  gzhSecret =SpringUtils.getBean(WeChatProperty.class).getGzhSecret();
    private String  gzhUrl =SpringUtils.getBean(WeChatProperty.class).getGzhUrl();
    private String wxGzhApi = SpringUtils.getBean(WeChatProperty.class).getWxGzhApi();
    /**
     * 查询小程序用户
     *
     * @param id 小程序用户主键
     * @return 小程序用户
     */
    @Override
    public AUser selectAUserById(Long id)
    {
        return aUserMapper.selectAUserById(id);
    }

    /**
     * 查询小程序用户列表
     *
     * @param aUser 小程序用户
     * @return 小程序用户
     */
    @Override
    public List<AUser> selectAUserList(AUser aUser)
    {
        return aUserMapper.selectAUserList(aUser);
    }

    /**
     * 新增小程序用户
     *
     * @param aUser 小程序用户
     * @return 结果
     */
    @Override
    public int insertAUser(AUser aUser)
    {
        aUser.setCreateTime(DateUtils.getNowDate());
        return aUserMapper.insertAUser(aUser);
    }

    /**
     * 修改小程序用户
     *
     * @param aUser 小程序用户
     * @return 结果
     */
    @Override
    public int updateAUser(AUser aUser)
    {
        aUser.setUpdateTime(DateUtils.getNowDate());
        return aUserMapper.updateAUser(aUser);
    }

    /**
     * 调整小程序用户身份
     *
     * @param aUser 小程序用户
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateAUseridentity(AUserDto aUser) throws IOException, WxErrorException {
        String role = aUser.getRole();
        String newRole = aUser.getNewRole();
        Long newTeamId = aUser.getTeamId();
        Long aUserId = aUser.getId();

        Assert.notNull(aUserId, "用户不能为空");
        Assert.notNull(role, "角色不能为空");
        Assert.notNull(newRole, "新角色不能为空");
        if(StringUtils.equals(newRole, "1")){
            Assert.notNull(newTeamId, "团队不能为空");
            ATeam aTeam = aTeamService.selectATeamById(newTeamId);
            Assert.notNull(aTeam, "团队不存在");
        }

        //查询用户原来的团队ID
        ATeamInfo aTeamInfo = new ATeamInfo();
        aTeamInfo.setUserId(aUserId);
        ATeamInfo teamInfo = aTeamInfoMapper.selectATeamInfoByUser(aTeamInfo);
        Long oldTeamId = null;
        if(!StringUtils.equals(role, "2")){
            Assert.notNull(teamInfo, "用户不存在");
            oldTeamId = teamInfo.getTeamId();
            Assert.notNull(oldTeamId, "团队不存在");
        }

        /*修改3处
        1.用户表 用户角色
        2.团队成员表 成员记录 - 原来的/新的
        3.用户团队表 成员数量 - 原来的/新的*/

        AUser us = new AUser();
        us.setId(aUserId);
        us.setRole(newRole);

        if(StringUtils.equals(role, "0")){
            //当前角色-代理商
            if(StringUtils.equals(newRole, "1")){
                //删除原来团队成员记录
                aTeamMapper.reduceTeamNum(oldTeamId);
                //减少原来团队成员数量
                aTeamInfoMapper.deleteATeamInfoById(teamInfo.getId());
                //删除原来团队的代理商
                aTeamMapper.updateATeamUserId(oldTeamId);

                //增加新团队成员记录,自己不能加入自己
                ATeamInfo infor = new ATeamInfo();
                infor.setUserId(aUserId);
                ATeamInfo atInfo = aTeamInfoMapper.selectATeamInfoByUser(infor);
                com.ruoyi.common.utils.Assert.Null(atInfo,"已加入团队！");
                ATeamVO atem =  aTeamMapper.selectATeamById(newTeamId);
                com.ruoyi.common.utils.Assert.notEquals(atem.getUserId(),aUserId,"用户已经是团长！");

                Date now = DateUtils.getNowDate();
                ATeamInfo info = new ATeamInfo();
                info.setReviewStatus("1");
                info.setApplicationTime(now);
                info.setCreateTime(now);
                info.setThroughTime(now);
                info.setTeamId(newTeamId);
                info.setUserId(aUserId);
                info.setIsAgent("1");
                aTeamInfoMapper.insertATeamInfo(info);

                //增加新团队成员数量
                aTeamMapper.addTeamNum(newTeamId);
            }else if(StringUtils.equals(newRole, "2")){
                //删除原来团队成员记录
                aTeamMapper.reduceTeamNum(oldTeamId);
                //减少原来团队成员数量
                aTeamInfoMapper.deleteATeamInfoById(teamInfo.getId());
                //删除原来团队的代理商
                aTeamMapper.updateATeamUserId(oldTeamId);
            }else{
                throw new ServiceException("角色不合法");
            }
        }else if(StringUtils.equals(role, "1")){
            //当前角色-团队成员
            if(StringUtils.equals(newRole, "0")){
                //删除原来团队成员记录
                aTeamMapper.reduceTeamNum(oldTeamId);
                //减少原来团队成员数量
                aTeamInfoMapper.deleteATeamInfoById(teamInfo.getId());

                //创建新团队 并设置为代理商
                ATeam team = new ATeam();
                team.setUserId(aUserId);
                team.setTeName(aUser.getPhone());
                aTeamService.insertATeam(team);
            }else if(StringUtils.equals(newRole, "2")){
                //删除原来团队成员记录
                aTeamMapper.reduceTeamNum(oldTeamId);
                //减少原来团队成员数量
                aTeamInfoMapper.deleteATeamInfoById(teamInfo.getId());
            }else{
                throw new ServiceException("角色不合法");
            }
        }else if(StringUtils.equals(role, "2")){
            //当前角色-普通用户
            if(StringUtils.equals(newRole, "0")){
                //创建新团队 并设置为代理商
                ATeam team = new ATeam();
                team.setUserId(aUserId);
                team.setTeName(aUser.getPhone());
                aTeamService.insertATeam(team);
            }else if(StringUtils.equals(newRole, "1")){
                //增加新团队成员记录,自己不能加入自己
                ATeamInfo infor = new ATeamInfo();
                infor.setUserId(aUserId);
                ATeamInfo atInfo = aTeamInfoMapper.selectATeamInfoByUser(infor);
                com.ruoyi.common.utils.Assert.Null(atInfo,"已加入团队！");
                ATeamVO atem =  aTeamMapper.selectATeamById(newTeamId);
                com.ruoyi.common.utils.Assert.notEquals(atem.getUserId(),aUserId,"用户已经是团长！");

                Date now = DateUtils.getNowDate();
                ATeamInfo info = new ATeamInfo();
                info.setReviewStatus("1");
                info.setApplicationTime(now);
                info.setCreateTime(now);
                info.setThroughTime(now);
                info.setTeamId(newTeamId);
                info.setUserId(aUserId);
                info.setIsAgent("1");
                aTeamInfoMapper.insertATeamInfo(info);

                //增加新团队成员数量
                aTeamMapper.addTeamNum(newTeamId);
            }else{
                throw new ServiceException("角色不合法");
            }
        }else{
            throw new ServiceException("角色参数错误");
        }
        us.setUpdateTime(DateUtils.getNowDate());
        return aUserMapper.updateAUser(us);
    }

    /**
     * 批量删除小程序用户
     *
     * @param ids 需要删除的小程序用户主键
     * @return 结果
     */
    @Override
    public int deleteAUserByIds(Long[] ids)
    {
        return aUserMapper.deleteAUserByIds(ids);
    }

    /**
     * 删除小程序用户信息
     *
     * @param id 小程序用户主键
     * @return 结果
     */
    @Override
    public int deleteAUserById(Long id)
    {
        return aUserMapper.deleteAUserById(id);
    }

    @Override
    public String miniLogin(AUser aUser)throws Exception {
        final WxMaService wxMaService = WeChatUtils.getMiniWxMaService();
        //获取openId
        WxMaJscode2SessionResult session = wxMaService.getUserService().getSessionInfo(aUser.getCode());
        System.out.println(session.getOpenid());

        Assert.notNull(session,"获取失败，请重新授权");

        WxMaPhoneNumberInfo phoneNoInfo = wxMaService.getUserService().getPhoneNoInfo(session.getSessionKey(),
                aUser.getEncryptedData(), aUser.getIv());
        Assert.notNull(phoneNoInfo.getPhoneNumber(), "获取手机号失败");

        AUser user = aUserMapper.selectAUserByOpenId(session.getOpenid());
        if(user == null){
            user = new AUser();
            user.setNickName(aUser.getNickName());
            user.setHeadImg(aUser.getHeadImg());
            user.setOpenId(session.getOpenid());
            user.setPhone(phoneNoInfo.getPhoneNumber());
            user.setRole("2");
            user.setCreateTime(DateUtils.getNowDate());
            user.setDownloadNum(0);
            aUserMapper.insertAUser(user);
        }else{
            user.setNickName(aUser.getNickName());
            user.setHeadImg(aUser.getHeadImg());
            aUserMapper.updateAUser(user);
        }
        return LoginUtils.login(user.getOpenId());
    }

    public String getPhone(AUser aUser) throws WxErrorException {
        final WxMaService wxMaService = WeChatUtils.getMiniWxMaService();
        WxMaPhoneNumberInfo phoneNoInfo = wxMaService.getUserService().getNewPhoneNoInfo(aUser.getCode());
        com.ruoyi.common.utils.Assert.notNull(phoneNoInfo.getPhoneNumber(), "获取手机号失败");
        return phoneNoInfo.getPhoneNumber();
    }

    @Override
    public int updateXcxAUser(AOperationRecords aOperationRecords) {
        OperTypeVO vo = new OperTypeVO();
        vo.setId(aOperationRecords.getId());
        vo.setOperType(1);

        //保存下载的用户信息
        AOperationRecords re = new AOperationRecords();
        re.setUserId(LoginUtils.getUser().getId());
        re.setOperType(1);
        re.setDataId(aOperationRecords.getId());
        re.setDataType(aOperationRecords.getOperType().toString());
        re.setCreateTime(DateUtils.getNowDate());
        re.setIsShow(true);
        re.setNumSoft(0);
        aOperationRecordsService.insertAOperationRecords(re);

        if("1".equals(aOperationRecords.getOperType().toString())){
            aInformationMapper.updateOper(vo);
        }
        if("2".equals(aOperationRecords.getOperType().toString())){
            aDataInfoMapper.updateOper(vo);
        }

        return aUserMapper.updateXcxAUser(LoginUtils.getUser().getOpenId());
    }

    @Override
    public int updateXcxUser(AUser aUser) {
        aUser.setId(LoginUtils.getUser().getId());
        aUser.setRealName(aUser.getRealName());
        return aUserMapper.updateAUser(aUser);
    }

    @Override
    public List<UserOperVO> UserOperList(UserOper userOper) {
        return aUserMapper.UserOperList(userOper);
    }

    @Override
    public String getOpenId(String code) throws Exception{
        final WxMaService wxMaService = WeChatUtils.getMiniWxMaService();
        //获取openId
        WxMaJscode2SessionResult session = wxMaService.getUserService().getSessionInfo(code);
        return session.getOpenid();
    }

    @Override
    public AjaxResult checkTxSecure(TxcheckVO vo) throws IOException {
        vo.setOpenId(LoginUtils.getUser().getOpenId());
        return TxCheckUtils.checkTx(vo);
    }

    @Override
    public List<AUser> selectAUserListAll() {
        return aUserMapper.selectAUserListAll();
    }

    @Override
    public String backtoken(String code) {
        if (org.apache.commons.lang3.StringUtils.isEmpty(code)) {
            new ServiceException("code不能为空");
        }
        //需要拿客户端获得的code换取openId
        String url = String.format(gzhUrl, gzhAppId, gzhSecret, code);
        //调用微信api授权
        String data = HttpClientUtil.doGet(url);
//        System.out.println("请求结果：" + data);
        //解析返回的json字符串
        JSONObject jsonObject = JSONObject.parseObject(data);
        //获取openid和token值
        String miniopenId = jsonObject.getString("openid");
        if(miniopenId == null){
            new ServiceException("未获取到openId");
        }
        String accessToken = jsonObject.getString("access_token");

        if (org.apache.commons.lang3.StringUtils.isEmpty(miniopenId)) {
            new ServiceException("未获取到openId");
        }
        // 通过openid 和 accessToken 来获取用户信息
        // 拼接请求地址
        String requestUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID";
        requestUrl = requestUrl.replace("ACCESS_TOKEN", accessToken).replace("miniopenId", miniopenId);
        //发送请求
        String urlRequest = HttpClientUtil.doGet(requestUrl);
        //解析返回的json字符串
        JSONObject userInfo = JSONObject.parseObject(urlRequest);
        //获取用户微信昵称和头像
        String nickname = userInfo.getString("nickname");
//        System.out.println(nickname);
        String avatar = userInfo.getString("headimgurl");

        AUser user = aUserMapper.selectUserByMiniOpenId(miniopenId);
        if(user == null){
            user = new AUser();
            user.setNickName(nickname);
            user.setHeadImg(avatar);
            user.setMiniOpenId(miniopenId);
            user.setPhone("");
            user.setRole("2");
            user.setCreateTime(DateUtils.getNowDate());
            user.setDownloadNum(0);
            aUserMapper.insertAUser(user);
        }else{
            user.setNickName(nickname);
            user.setHeadImg(avatar);
            aUserMapper.updateAUser(user);
        }
        return LoginUtils.loginMini(user.getMiniOpenId());
    }


    @Override
    public WxTokenVO getWxToken() {
        WxTokenVO vo = new WxTokenVO();
        String token = "";
        String path = "token?grant_type=client_credential&appid=" + gzhAppId + "&secret=" + gzhSecret;
        String body = HttpUtil.createGet(wxGzhApi + path)
                .execute()
                .body();
        JSONObject object = JSON.parseObject(body);
        //获取token
        token = object.getString("access_token");
        //失效时间
        String expires_in = object.getString("expires_in");

        //将token值的值放在redis里面
        redisService.setCacheObject("gzh_access_token", token,7190, TimeUnit.SECONDS);
        vo.setToken(token);
        return vo;
    }

    @Override
    public WxTicketVO getJsapiTicket() {
        WxTicketVO vo = new WxTicketVO();
        Object access_token = redisService.getCacheObject("gzh_access_token");
        if (access_token == null) {
            access_token = getWxToken();
        }
        String path = "ticket/getticket?access_token=" + access_token.toString() + "&type=jsapi";
        String body = HttpUtil.createGet(wxGzhApi + path)
                .execute()
                .body();
        JSONObject object = JSON.parseObject(body);
        //获取ticket
        String ticket = object.getString("ticket");
        //错误码
        Integer errcode = object.getInteger("errcode");
        if(errcode==0){
            //将ticket值的值放在redis里面
            redisService.setCacheObject("gzh_ticket", ticket,7190,TimeUnit.SECONDS);
        }
        vo.setTicket(ticket);
        return vo;
    }

    @Override
    public WxSignVO getUserSign(WxSignVO sign) {
        WxSignVO vo = new WxSignVO();
        Object ticket = redisService.getCacheObject("gzh_ticket");
        if(ticket == null) {
            ticket = getJsapiTicket();
        }
        Map<String, String> ret = WxSignUtil.sign(ticket.toString(), sign.getUrl());
        vo.setTimestamp(ret.get("timestamp"));
        vo.setNonceStr(ret.get("nonceStr"));
        vo.setSignature(ret.get("signature"));
        vo.setUrl(ret.get("url"));
        return vo;
    }

    @Override
    public AUser getGzhUser() {
        String miniOpenId = LoginUtils.getUser().getMiniOpenId();
        return aUserMapper.selectUserByMiniOpenId(miniOpenId);
    }
}
